package com.ev.asl.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ev.asl.service.KisBasicsService;
import com.ev.custom.domain.*;
import com.ev.custom.service.DictionaryService;
import com.ev.framework.config.Constant;
import com.ev.framework.utils.HttpClientUtils;
import com.ev.framework.utils.R;
import com.ev.framework.utils.ShiroUtils;
import com.ev.framework.utils.StringUtils;
import com.ev.asl.config.ApiParam;
import com.ev.asl.config.JiateConstant;
import com.ev.asl.config.KisApiUrlParam;
import com.ev.asl.dao.BasicsDao;
import com.ev.asl.domain.KisStockDO;
import com.ev.asl.service.KisStockService;
import com.ev.asl.vo.*;
import com.ev.asl.vo.voBillOfPull.*;
import com.ev.system.domain.DeptDO;
import com.ev.system.domain.UserDO;
import com.ev.system.service.DeptService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;

@Slf4j
@Service
public class KisBasicsServiceImpl implements KisBasicsService {
    @Resource
    private BasicsDao basicsDao;
    @Autowired
    private DictionaryService dictionaryService;

    @Resource
    private KisApiUrlParam kisApiUrlParam;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DeptService sysDeptService;
    @Autowired
    private KisStockService kisStockService;


    //时间转换  ---> String  Date
    public static Date timeToTranslateForDate(String strDate) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ParsePosition pos = new ParsePosition(0);
        Date stToDate = formatter.parse(strDate, pos);
        return stToDate;
    }

    /**
     * 获取已同步数据，比对新数据判断更新或新增
     * @param sign
     * @return
     */
    public Map<Long, Long> getAllOldIds(int sign) {
        List<Map<String, Object>> allIds = new ArrayList<>();
        switch (sign) {
            case 1:
                //物料
                allIds = basicsDao.getMaterialIds();
                break;
            case 2:
                //仓库
                allIds = basicsDao.getWareHouseIds();
                break;
            case 3:
                //客户
                allIds = basicsDao.getClientIds();
                break;
            case 4:
                //供应商
                allIds = basicsDao.getSupplierIds();
                break;
            case 5:
                //部门
                allIds = basicsDao.getDepartIds();
                break;
            case 6:
                //仓位
                allIds = basicsDao.getFacilityLocation();
                break;
            case 7:
                //物料类型
                allIds = basicsDao.getMaterielTypeIds();
                break;
            default:
                break;
        }
        Map<Long, Long> ids = new HashMap<>();
        if (!CollectionUtils.isEmpty(allIds)&& !Objects.equals(sign,1)) {
            allIds.stream().forEach(aa -> {
                Long id = Long.parseLong(aa.get("id").toString());
                ids.put(id, id);
            });
        }
        if (Objects.equals(sign,1)) {
            allIds.stream().forEach(aa -> {
                Long id = Long.parseLong(aa.get("id").toString());
                Long idd = aa.get("idd")==null?0L:Long.parseLong(aa.get("idd").toString());
                ids.put(id, idd);
            });
        }
        return ids;
    }

    public Map<Long, String> getAllOldIdsBySign(int sign) {
        List<Map<String, Object>> allIds = new ArrayList<>();
        switch (sign) {
            case 1:
                //用户  返回 主键和密码
                allIds = basicsDao.getUserIds();
                break;
            case 2:
                //部门  返回 主键和父主键
                allIds = basicsDao.getDepartIds();
                break;
            case 100:
                //计量单位
                allIds = basicsDao.getDictionaryIds(JiateConstant.UOM_TYPE);
                break;
            case 101:
                //计量单位
                allIds = basicsDao.getDictionaryIds(JiateConstant.FAC_TYPE);
                break;
            default:
                break;
        }
        Map<Long, String> ids = new HashMap<>();
        if (!CollectionUtils.isEmpty(allIds)) {
            allIds.stream().forEach(aa -> {
                Long id = Long.parseLong(aa.get("id").toString());
                ids.put(id, aa.get("ids").toString());
            });
        }
        return ids;
    }

/**-----------------------------------------------------------------------------------------------------------------------*/

    /**
     * 物料
     */

    @Override
    public R materielDataByParam(int itemClassId) {
        //查询出物料的所有的主键
        //90秒中内禁止重复同步操作
        String key = "_materiel_all";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("物料数据量巨大，禁止频繁操作同步！请200秒后重试");
        }
        //同一个登录人90秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 200l, TimeUnit.SECONDS);

        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId,true);
        //TODO   上线改为 2000
        paramForApi.put("PageSize", "500");
        paramForApi.remove("QueryType");
        // TODO 异步执行计量单位的同步
        this.unitOfMeasurement();
        //异步执行同步物料
        this.doPostOfApiForMateriel(kisApiUrlParam.getUrl_basic(), paramForApi);
        return R.ok("系统正在拼命同步数量众多的物料信息，请稍后刷新列表！");
    }

    @Async("createPDFExecutor")
    public R doPostOfApiForMateriel(String url, Map<String, String> params) {

        // 创建HttpClient对象
        HttpClient httpClient = HttpClientBuilder.create().build();
        HttpPost httpPost = new HttpPost(url);
        //获取单位
        Map<Long, String> allOldIdsOfUnit = getAllOldIdsBySign(JiateConstant.UNIT);
        try {
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("Accept", "application/json");
            //TODO   上线循环  i改为 8   Integer.MAX_VALUE
            for (int i = 1; i < 8 ; i++) {
                params.put("PageNo", String.valueOf(i));
                log.info("---参数为params:" + JSONObject.toJSONString(params));
                String paramstr = JSONObject.toJSONString(params);
                if (StringUtils.isNotBlank(paramstr)) {
                    httpPost.setEntity(new StringEntity(paramstr, Charset.forName("UTF-8")));
                }
                HttpResponse response = httpClient.execute(httpPost);
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    String result = EntityUtils.toString(response.getEntity());
                    Object parse = JSON.parse(result);
                    ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
                    log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
                    if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                        // 0 为正常  1 异常
                        return R.error("同步api 返回值异常：" + apiResultVOS.getMsg());
                    }
                    String datas = apiResultVOS.getDatas();
                    List<KisMaterielVO> kisMaterielVO = JSON.parseArray(datas, KisMaterielVO.class);
                    if (!CollectionUtils.isEmpty(kisMaterielVO)) {
                        // --->禁止使用多线程保存更新
                        dailyStatistics(kisMaterielVO, i,allOldIdsOfUnit);
                    } else {
                        log.info("已无数据返回！");
                        break;
                    }
                } else {
                    log.info("api 连接异常！，返回状态码为：" + response.getStatusLine().getStatusCode());
                    if (i > 5) {
                        return R.error("Api返回错误状态码，同步失败！请管理员检查api");
                    }
                }
            }
            return R.ok("同步完毕!");
        } catch (Exception e) {
            log.info("请求失败!");
            log.error(e.getMessage());
            return R.error("请求同步失败！请管理员检查api");
        } finally {
            // 释放连接
            if (null != httpPost) {
                httpPost.releaseConnection();
            }
        }
    }

    /**
     * 处理
     */
    public void dailyStatistics(List<KisMaterielVO> kisResults, int sign, Map<Long, String> allOldIdsOfUnit) {
        try {
            Map<Long, Long> materialIds = getAllOldIds(1);
            //字段匹配转换
            List<MaterielDO> materielDOS = fieldMatchingConversion(kisResults,allOldIdsOfUnit);
            log.info("循环次数: " + sign + " 执行保存更新  开始！");
            try {
                List<MaterielDO> updateMateriel = new ArrayList<>();
                List<MaterielDO> saveMateriel = new ArrayList<>();
                for (MaterielDO vo : materielDOS) {
                    Long id = vo.getId();
                    if (materialIds.containsKey(id)) {
                        //更新
                        vo.setCheckPlanId(materialIds.get(id));
                        updateMateriel.add(vo);
                    } else {
                        //新增
                        saveMateriel.add(vo);
                    }
                }
                log.info("---------------更新的-----------------------");
                log.info(JSON.toJSONString(updateMateriel));
                if (!CollectionUtils.isEmpty(updateMateriel)) {
                    int i = basicsDao.batchUpdate(updateMateriel);
                    log.info("---------------更新-完成 - " + i);
                }
                if (!CollectionUtils.isEmpty(saveMateriel)) {
                    int ii = basicsDao.batchSave(saveMateriel);
                    log.info("---------------保存 完成 -- " + ii);
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.info("线程: " + sign + " 异步保存更新物料  异常！" + e.getMessage());
            }
            log.info("循环次数: " + sign + " 异步保存更新物料   结束！");
        } catch (Exception e) {
            log.info("---------------保存更新异常--" + e.getMessage());
        }
    }

    public List<MaterielDO> fieldMatchingConversion(List<KisMaterielVO> kisResults, Map<Long, String> allOldIdsOfUnit) {
        //查询出所有物料类型
        Map<Long, Long> materialTypeIds = getAllOldIds(7);
        List<MaterielTypeDO> saveType = new ArrayList<>(kisResults.size());
        List<MaterielTypeDO> updateType = new ArrayList<>(kisResults.size());
        Map<Long, Long> typeIds = Maps.newHashMapWithExpectedSize(kisResults.size());
        Date date = new Date();
        List<MaterielDO> materielDOS = new ArrayList<>();
        for (KisMaterielVO vo : kisResults) {
            MaterielDO materielDO = new MaterielDO();
            materielDO.setId(Long.parseLong(vo.getFItemId()));
            materielDO.setSerialNo(vo.getFNumber());
            materielDO.setSpecification(vo.getFModel());
            materielDO.setVolume(ObjectUtils.isEmpty(vo.getFNetWeight()) ? null : vo.getFSize().contains(".") ? new BigDecimal(vo.getFSize().substring(0,vo.getFSize().indexOf(".")+3)) : null);
            materielDO.setNetWeight(ObjectUtils.isEmpty(vo.getFNetWeight()) ? null : vo.getFNetWeight().contains(".") ? new BigDecimal(vo.getFNetWeight().substring(0,vo.getFNetWeight().indexOf(".")+3)) : null);
            log.error("体积："+new BigDecimal(vo.getFSize()));
            log.error("重量："+new BigDecimal(vo.getFNetWeight()));
            log.error("体积2："+materielDO.getVolume());
            log.error("重量2："+materielDO.getNetWeight());
            materielDO.setName(vo.getFName());
            //物料属性
            materielDO.setAttribute(Long.parseLong(vo.getFErpClsID()));
            //物料分类
            Long materialType = Objects.equals(Long.parseLong(vo.getFTypeID()),0L)?1L:Long.parseLong(vo.getFTypeID());
            materielDO.setType(materialType);
            if (!typeIds.containsKey(materialType)) {
                MaterielTypeDO typeDO = new MaterielTypeDO();
                typeDO.setName(vo.getFTypeID_FName() == null || vo.getFTypeID_FName() == "" ? "默认类型" : vo.getFTypeID_FName());
                typeDO.setId(materialType);
                if (materialTypeIds.containsKey(materialType)) {
                    updateType.add(typeDO);
                } else {
                    saveType.add(typeDO);
                }
            }
            typeIds.put(materialType,materialType);
            //加特要求主辅单位一致
            //计量单位
            Long fUnitID = Long.parseLong(vo.getFUnitID());
            Long umo = allOldIdsOfUnit.containsKey(fUnitID)?Long.parseLong(allOldIdsOfUnit.get(fUnitID)):0L;
            materielDO.setUnitUom(umo);
            //辅助单位
//            Long FSecUnitID =  Long.parseLong(vo.getFSecUnitID());
//            materielDO.setSupportUom(allOldIdsOfUnit.containsKey(FSecUnitID)?Long.parseLong(allOldIdsOfUnit.get(FSecUnitID)):0L);
            materielDO.setSupportUom(umo);
            //仓库
            materielDO.setDefaultFacility(Long.parseLong(vo.getFDefaultLoc()));
            //仓位
            materielDO.setDefaultLocation(Long.parseLong(vo.getFSPID()));
            //换算率    因返回的数据为科学计数法无法解析 暂时 放置为1
//            materielDO.setConvCoefficient(BigDecimal.valueOf(Long.parseLong(vo.getFSecCoefficient())));
            materielDO.setConvCoefficient(new BigDecimal("1"));
            //使用状态
            String det = vo.getFUseState_FName() != null ? vo.getFUseState_FName() : "";
            // TODO   默认物料都为使用状态
            materielDO.setDelFlag(0);
            materielDO.setCreateTime(date);
            materielDO.setUpdateTime(date);
            materielDO.setCheckPlanId(44l);
            materielDO.setAuditSign(Constant.OK_AUDITED);
            materielDO.setUseStatus(det.equals("使用") ? 1 : 0);
            materielDOS.add(materielDO);
        }
        //异步保存物料类型
        typeOfMaterialHandled(saveType,updateType);
        return materielDOS;
    }

    /**
     * 异步处理物料类型
     */
    @Async("createPDFExecutor")
    public  void typeOfMaterialHandled(List<MaterielTypeDO> saveType, List<MaterielTypeDO> updateType){
        if(!CollectionUtils.isEmpty(saveType)){
            basicsDao.batchSaveMaterialTYpe(saveType);
        }
        if(!CollectionUtils.isEmpty(updateType)){
            basicsDao.batchUpdateMaterialTYpe(updateType);
        }
        log.info("----------异步更新 保存 物料类型 结束！");
    }


/**-----------------------------------------------------------------------------------------------------------------------*/

    /**
     * 同步 kis 仓库
     */
    @Override
    public R wareHouseDataByParam(int itemClassId) {
        //查询出物料的所有的主键
        //90秒中内禁止重复同步操作
        String key = ShiroUtils.getUserId() + "_wareHouse";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("禁止频繁操作同步！请60秒后重试");
        }
        //同一个登录人60秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 6l, TimeUnit.SECONDS);

        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId,true);
        //TODO   上线改为 5000
        paramForApi.put("PageSize", "500");
        return this.doPostOfApiForWareHouse(kisApiUrlParam.getUrl_basic(), paramForApi);
    }

    public R doPostOfApiForWareHouse(String url, Map<String, String> params) {
        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<KisWareHouseVO> kisWareHouseVO = JSON.parseArray(datas, KisWareHouseVO.class);
            if (!CollectionUtils.isEmpty(kisWareHouseVO)) {
                //单线程保存 更新
                keepUpdateForWareHouse(kisWareHouseVO);
            }
        }
        return R.ok();
    }

    public void keepUpdateForWareHouse(List<KisWareHouseVO> kisWareHouseVO) {
        log.info(" 保存更新 仓库  开始！");
        //字段匹配转换
        Pair<List<FacilityDO>, List<FacilityDO>> listPair = fieldMatchingConversionOfWareHouse(kisWareHouseVO);
//        try {
            List<FacilityDO> updateDo = listPair.getRight();
            List<FacilityDO> saveDo = listPair.getLeft();
            if (!CollectionUtils.isEmpty(updateDo)) {
                int i = basicsDao.batchUpdateWareHose(updateDo);
                log.info("---------------更新-完成 - " + i);
            }
            if (!CollectionUtils.isEmpty(saveDo)) {
                int ii = basicsDao.batchSaveHaveIdWareHose(saveDo);
                log.info("---------------保存 完成 -- " + ii);
            }

            //异步更新仓位
            log.info("---------------异步更新仓位 -- ");
            freightSpaceByParam(JiateConstant.WAREHOUSE_OR_LOCATION);

//        } catch (Exception e) {
//            e.printStackTrace();
//            log.info(" 保存更新仓库  异常！");
//        }
        log.info(" 保存更新 仓库  结束！");
    }

    public Pair<List<FacilityDO>,List<FacilityDO>> fieldMatchingConversionOfWareHouse(List<KisWareHouseVO> kisWareHouseVO) {
        Date date = new Date();
        //字典仓库类型
        Map<Long, String> allOldIdsBySignOfDic = getAllOldIdsBySign(101);
        List<FacilityDO> facilityDOs = new ArrayList<>();
        List<DictionaryDO> dictionaryDO = new ArrayList<>();
        Boolean sign = false;
        Map<Long,Long> map = Maps.newHashMapWithExpectedSize(kisWareHouseVO.size());
        for (KisWareHouseVO vo : kisWareHouseVO) {
            FacilityDO facilityDO = new FacilityDO();
            facilityDO.setId(Long.parseLong(vo.getFItemId()));
            facilityDO.setSerialNo(vo.getFNumber());
            facilityDO.setName(vo.getFName());
            facilityDO.setCreateTime(date);
            facilityDO.setUpdateTime(date);
            //仓位组 对应仓位
            log.info("-----------------------------vo.getFSPGroupID()"+vo.getFSPGroupID());
            if(StringUtils.isNotBlank(vo.getFSPGroupID())){
                facilityDO.setGroupId(Long.parseLong(vo.getFSPGroupID()));
            }
            //删除  默认都为未删除
            facilityDO.setDelFlag(0);
            facilityDO.setAuditSign(179L);
            //  TODO    仓库类型
            Long fTypeId = Long.parseLong(vo.getFTypeID());
            facilityDO.setFacilityType(fTypeId);
            if(!allOldIdsBySignOfDic.containsKey(fTypeId) && !map.containsKey(fTypeId)){
                //字典中新增仓库类型
                DictionaryDO dic = new DictionaryDO();
                dic.setName(vo.getFTypeID_FName());
                dic.setMeasureUnitId(fTypeId);
                dic.setDelFlag(0);
                dic.setValue("type_ware_hose");
                //仓库类型
                dic.setTypeId(2L);
                dictionaryDO.add(dic);
                map.put(fTypeId,fTypeId);
            }
            facilityDOs.add(facilityDO);
        }
        if(!CollectionUtils.isEmpty(dictionaryDO)){
            //字典新增仓库类型
            basicsDao.batchSaveDictionary(dictionaryDO);
            sign = true;
        }
        if(sign){
            allOldIdsBySignOfDic = getAllOldIdsBySign(101);
        }
        List<FacilityDO> updateDO = new ArrayList<>();
        List<FacilityDO> saveDO = new ArrayList<>();
        Map<Long, Long> allOldIds = getAllOldIds(2);
        for (FacilityDO vo : facilityDOs) {
            Long id  = vo.getId();
            Long facilityType = vo.getFacilityType();
            if(allOldIdsBySignOfDic.containsKey(facilityType)){
                vo.setFacilityType(Long.parseLong(allOldIdsBySignOfDic.get(facilityType)));
            }
            if (allOldIds.containsKey(id)) {
                //更新
                updateDO.add(vo);
            } else {
                //新增
                saveDO.add(vo);
            }
        }
        return Pair.of(saveDO,updateDO);
    }

    /**-----------------------------------------------------------------------------------------------------------------------*/

    /**
     * 同步 kis 仓位   绑定仓库一起同步
     */
    @Async("createPDFExecutor")
    @Override
    public R freightSpaceByParam(int itemClassId) {
        //90秒中内禁止重复同步操作
//        String key = "_wareHouse_of_freight_space";
//        Object value = redisTemplate.opsForValue().get(key);
//        if (Objects.nonNull(value)) {
//            return R.error("禁止频繁操作同步！请180秒后重试");
//        }
//        //同一个登录人180秒内只可以操作一次
//        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 180l, TimeUnit.SECONDS);
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId,true);
        return this.doPostOfApiForFreightSpace(kisApiUrlParam.getUrl_base_data(), paramForApi);
    }

    public R doPostOfApiForFreightSpace(String url, Map<String, String> params) {
        //TODO   上线改为 5000
        params.put("PageSize", "5000");
        params.put("QueryFields", "");
        for(int i=1;i<2;i++){
            params.put("PageNo", String.valueOf(i));
            String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
            if (StringUtils.isNotBlank(result)) {
                Object parse = JSON.parse(result);
                ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
//                log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
                if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                    // 0 为正常  1 异常
                    return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
                }
                String datas = apiResultVOS.getDatas();
                List<KisWareLocationVO> kisWareLocationVO = JSON.parseArray(datas, KisWareLocationVO.class);
                if (!CollectionUtils.isEmpty(kisWareLocationVO)) {
                    //单线程保存 更新
                    keepUpdateForWareHouseLocation(kisWareLocationVO);
                }else{
                    break;
                }
            }else{
                break;
            }
        }
        return R.ok();
    }

    public void  keepUpdateForWareHouseLocation( List<KisWareLocationVO> kisWareLocationVO ){
        //之前同步的老数据
        Map<Long, Long> allOldIds = getAllOldIds(6);
        List<FacilityLocationDO> updateVO = new ArrayList<>();
        List<FacilityLocationDO> saveVO = new ArrayList<>();
        for (KisWareLocationVO aa : kisWareLocationVO) {
            FacilityLocationDO vo = new FacilityLocationDO();
            vo.setName(aa.getFName());
            vo.setSerialNo(aa.getFNumber());
            vo.setDescription(aa.getFFullName());
            //仓库主键 存  仓库组主键FSpGroupId
            vo.setFacilityId(Long.parseLong(aa.getFSpGroupId()));
            vo.setRemarks(aa.getFDescription());
            vo.setDelFlag(0);
            vo.setAuditSign(179L);
            vo.setAuditor(1L);
            long fspid = Long.parseLong(aa.getFSPID());
            vo.setId(fspid);
            if(allOldIds.containsKey(fspid)){
                updateVO.add(vo);
            }else{
                saveVO.add(vo);
            }
        }
        if(!CollectionUtils.isEmpty(saveVO)){
            basicsDao.batchSaveLocation(saveVO);
        }
        if(!CollectionUtils.isEmpty(updateVO)){
            basicsDao.batchUpdateLocation(updateVO);
        }
    }
/**----------------------------------------------------------------------------------------------------------------------- */

    /**
     * 同步 kis 系统用户
     */
    public Map<String,String> userDataByParamsFromKis() {
        String params  = "{\"Acct\":\"XRTEST\"}" ;
        String result = HttpClientUtils.sendJsonStr(kisApiUrlParam.getUrl_base_user(), JSONObject.toJSONString(params));
        Map<String,String> map = Maps.newHashMapWithExpectedSize(16);
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                log.info("同步api 系统用户 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<KisUsersVO> kisUserVOs = JSON.parseArray(datas, KisUsersVO.class);
            if (!CollectionUtils.isEmpty(kisUserVOs)) {
                //单线程保存 更新
                kisUserVOs.stream().forEach(aa->{
                    map.put(aa.getFName(),aa.getFUserId());
                });
            }
        }
        return map;
    }

/**----------------------------------------------------------------------------------------------------------------------- */

    /**
     * 同步 kis 用户
     */
    @Override
    public R userDataByParam(int itemClassId) {
        String key = ShiroUtils.getUserId() + "_allUser";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("禁止频繁操作同步！请60秒后重试");
        }
        //同一个登录人60秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 60l, TimeUnit.SECONDS);
        //查询出用户的所有的主键
        Map<Long, String> allOldIds = getAllOldIdsBySign(1);
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId,true);
        //TODO   上线改为 5000
        paramForApi.put("PageSize", "5000");
        return this.doPostOfApiForUser(kisApiUrlParam.getUrl_basic(), paramForApi, allOldIds);
    }

    public R doPostOfApiForUser(String url, Map<String, String> params, Map<Long, String> allOldIds) {
        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<KisUserVO> kisUserVOs = JSON.parseArray(datas, KisUserVO.class);
            if (!CollectionUtils.isEmpty(kisUserVOs)) {
                //查询系统用户信息
                List<KisUserVO> kisUserVOOfNeed = new ArrayList<>();
                Map<String, String> userNameAndId = this.userDataByParamsFromKis();
                if(!userNameAndId.isEmpty()){
                    kisUserVOs.stream().forEach(aa->{
                        for(String name:userNameAndId.keySet()){
                            if(Objects.equals(aa.getFName(),name)){
                                aa.setFUserId(userNameAndId.get(name));
                                kisUserVOOfNeed.add(aa);
                            }
                        }
                    });
                }
                if (!CollectionUtils.isEmpty(kisUserVOOfNeed)) {
                    List<KisUserVO> collect1 = kisUserVOs
                            .stream()
                            .collect(toMap(KisUserVO::getFName,
                                    Function.identity(),
                                    (o1, o2) -> o1))
                            .entrySet()
                            .stream()
                            .map(Map.Entry::getValue)
                            .collect(Collectors.toList());

                    this.keepUpdateForUser(collect1, allOldIds);
//                    this.keepUpdateForUser(kisUserVOs, allOldIds);
                }else{
                    return R.error("无系统用户可同步！");
                }
                //单线程保存 更新
//                keepUpdateForUser(kisUserVOs, allOldIds);
            }
        }
        return R.ok();
    }

    public void keepUpdateForUser(List<KisUserVO> kisUserVOs, Map<Long, String> allOldIds) {
        log.info(" 保存更新 用户   开始！");
        //字段匹配转换
        Pair<List<UserDO>, List<UserDO>> listListPair = fieldMatchingConversionOfUser(kisUserVOs, allOldIds);
        try {
            List<UserDO> updateUser = listListPair.getRight();
            if (!CollectionUtils.isEmpty(updateUser)) {
                int i = basicsDao.batchUpdateUser(updateUser);
                log.info("---------------更新-完成 - " + i);
            }
            List<UserDO> saveWareUser = listListPair.getLeft();
            if (!CollectionUtils.isEmpty(saveWareUser)) {
                int ii = basicsDao.batchSaveUser(saveWareUser);
                log.info("---------------保存 完成 -- " + ii);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新用户  异常！");
        }
        log.info(" 保存更新 用户  结束！");
    }

    public Pair<List<UserDO>,List<UserDO>> fieldMatchingConversionOfUser(List<KisUserVO> kisUserVOs, Map<Long, String> allOldIds) {
        Date date = new Date();
        List<UserDO> updateUser = new ArrayList<>();
        List<UserDO> saveUser = new ArrayList<>();
        log.info(" 111111111111111111111111111111111111111111111111111111111111111111");
        for (KisUserVO vo : kisUserVOs) {
            UserDO userDO = new UserDO();
            long id = Long.parseLong(vo.getFItemId());
            userDO.setUserId(id);
            log.info(" 222222222222222222222222222222222222222222222222222222222222222");
            userDO.setUserId2(ObjectUtils.isEmpty(vo.getFUserId()) ? null : Long.parseLong(vo.getFUserId()));
            //手机号   没有就放名字
            userDO.setUsername(vo.getFPhone()==null?vo.getFMobilePhone()==null?vo.getFName():vo.getFMobilePhone():vo.getFPhone());
            userDO.setName(vo.getFName());
            //密码  默认初始密码为 111111
            userDO.setPassword("11111");
            userDO.setDeptId(Long.parseLong(vo.getFDepartmentID()));
            userDO.setEmail(vo.getFEmail());
            userDO.setMobile(vo.getFMobilePhone()==null?vo.getFPhone():null);
            //离职日期如果有则为离职 user禁用
            userDO.setStatus(vo.getFLeaveDate()!=null?0:1);
            userDO.setDelFlag(0);
            userDO.setSex(Long.parseLong(vo.getFGender()));
            userDO.setCreateTime(date);

            if (allOldIds.containsKey(id)) {
                // 更新的用户 保留原密码
                userDO.setPassword(allOldIds.get(id));
                updateUser.add(userDO);
            }else{
                saveUser.add(userDO);
            }
        }
        return Pair.of(saveUser,updateUser);
    }


    /**----------------------------------------------------------------------------------------------------------------------- */

    /**
     * 同步 kis 客户
     */
    @Override
    public R clientDataByParam(int itemClassId) {
        String key = ShiroUtils.getUserId() + "_allClient";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("禁止频繁操作同步！请60秒后重试");
        }
        //同一个登录人60秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 60l, TimeUnit.SECONDS);
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId,true);
        //TODO   上线改为 5000
        paramForApi.put("PageSize", "5000");
        return this.doPostOfApiForClient(kisApiUrlParam.getUrl_basic(), paramForApi);
    }

    public R doPostOfApiForClient(String url, Map<String, String> params) {
        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<KisClientVO> kisClientVO = JSON.parseArray(datas, KisClientVO.class);
            if (!CollectionUtils.isEmpty(kisClientVO)) {
                //单线程保存 更新
                keepUpdateForClient(kisClientVO);
            }
        }
        return R.ok();
    }

    public void keepUpdateForClient(List<KisClientVO> kisClientVO) {
        log.info(" 保存更新 客户  开始！");
        //字段匹配转换
        //查询出用户的所有的主键
        Map<Long, Long> allOldIds = getAllOldIds(3);
        System.out.println("-----------------用户主键" +JSONObject.toJSONString(allOldIds));
        Pair<List<ClientDO>, List<ClientDO>> clientDOs = fieldMatchingConversionOfClient(kisClientVO, allOldIds);
        try {
            List<ClientDO> updateClient = clientDOs.getRight();
            if (!CollectionUtils.isEmpty(updateClient)) {
                int i = basicsDao.updateBatchSelectiveClient(updateClient);
                log.info("---------------更新-完成 - " + i);
            }
            List<ClientDO> saveClient = clientDOs.getLeft();
            if (!CollectionUtils.isEmpty(saveClient)) {
                int ii = basicsDao.batchSaveClient(saveClient);
                log.info("---------------保存 完成 -- " + ii);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新客户  异常！");
        }
        log.info(" 保存更新 客户  结束！");
    }

    public  Pair<List<ClientDO>,List<ClientDO>> fieldMatchingConversionOfClient(List<KisClientVO> kisClientVO, Map<Long, Long> allOldIds) {
        Date date = new Date();
        List<ClientDO> updateClient = new ArrayList<>();
        List<ClientDO> saveClient = new ArrayList<>();
        for (KisClientVO vo : kisClientVO) {
            ClientDO clientDO = new ClientDO();
            Long id = Long.parseLong(vo.getFItemId());
            clientDO.setId(id);
            clientDO.setCode(vo.getFNumber());
            clientDO.setName(vo.getFName());
            //客户类型
            clientDO.setType(Long.parseLong(vo.getFTypeID()));
            clientDO.setPhone(vo.getFMobilePhone()==null?vo.getFPhone():vo.getFMobilePhone());
            clientDO.setAddress(vo.getFAddress());
            clientDO.setLegalperson(vo.getFcorperate());
            clientDO.setBank(vo.getFBank());
            clientDO.setAccount(vo.getFAccount());
            clientDO.setDelFlag(0);
            //使用状体
            clientDO.setStatus(Objects.equals("使用",vo.getFStatus_FName())?179L:178);
            clientDO.setUseStatus(Objects.equals("使用",vo.getFStatus_FName())?1:0);
            clientDO.setUpdateTime(date);
            if (allOldIds.containsKey(id)) {
                updateClient.add(clientDO);
            }else{
                saveClient.add(clientDO);
            }
        }
        return Pair.of(saveClient,updateClient);
    }


    /**----------------------------------------------------------------------------------------------------------------------- */

    /**
     * 同步 kis 供应商
     */
    @Override
    public R supplierDataByParam(int itemClassId) {
        String key = ShiroUtils.getUserId() + "_allSupplier";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("禁止频繁操作同步！请60秒后重试");
        }
        //同一个登录人60秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 60l, TimeUnit.SECONDS);
        //查询出用户的所有的主键
        Map<Long, Long> allOldIds = getAllOldIds(4);
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId,true);
        //TODO   上线改为 5000
        paramForApi.put("PageSize", "5000");
        return this.doPostOfApiForSupplier(kisApiUrlParam.getUrl_basic(), paramForApi, allOldIds);
    }

    public R doPostOfApiForSupplier(String url, Map<String, String> params, Map<Long, Long> allOldIds) {
        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<KisSupplierVO> kisSupplierVO = JSON.parseArray(datas, KisSupplierVO.class);
            if (!CollectionUtils.isEmpty(kisSupplierVO)) {
                //单线程保存 更新
                keepUpdateForSupplier(kisSupplierVO, allOldIds);
            }
        }
        return R.ok();
    }

    public void keepUpdateForSupplier(List<KisSupplierVO> kisSupplierVO, Map<Long, Long> allOldIds) {
        log.info(" 保存更新 供应商  开始！");
        //字段匹配转换
        Pair<List<SupplierDO>, List<SupplierDO>> SupplierDOs = fieldMatchingConversionOfSupplier(kisSupplierVO, allOldIds);
        try {
            List<SupplierDO> updateSupplier = SupplierDOs.getRight();
            if (!CollectionUtils.isEmpty(updateSupplier)) {
                int i = basicsDao.batchUpdateSupplier(updateSupplier);
                log.info("---------------更新-完成 - " + i);
            }
            List<SupplierDO> saveSupplier = SupplierDOs.getLeft();
            if (!CollectionUtils.isEmpty(saveSupplier)) {
                int ii = basicsDao.batchSaveSupplier(saveSupplier);
                log.info("---------------保存 完成 -- " + ii);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新 供应商  异常！");
        }
        log.info(" 保存更新 供应商  结束！");
    }

    public  Pair<List<SupplierDO>,List<SupplierDO>> fieldMatchingConversionOfSupplier(List<KisSupplierVO> kisClientVO, Map<Long, Long> allOldIds) {
        Date date = new Date();
        List<SupplierDO> updateSupplier = new ArrayList<>();
        List<SupplierDO> saveSupplier = new ArrayList<>();
        for (KisSupplierVO vo : kisClientVO) {
            SupplierDO supplierDO = new SupplierDO();
            Long id = Long.parseLong(vo.getFItemId());
            supplierDO.setId(id);
            supplierDO.setCode(vo.getFNumber());
            supplierDO.setName(vo.getFName());
            supplierDO.setType(Long.parseLong(vo.getFTypeID()));
            supplierDO.setPhone(vo.getFMobilePhone());
            supplierDO.setFax(vo.getFPhone());
            supplierDO.setAddress(vo.getFAddress());
            supplierDO.setLegalperson(vo.getFcorperate());
            supplierDO.setCreateTime(date);
            supplierDO.setDelFlag(0);
            supplierDO.setBank(vo.getFBank());
            supplierDO.setAccount(vo.getFAccount());
            //使用状体
            supplierDO.setStatus(Objects.equals("使用",vo.getFStatus_FName())?179L:178);
            supplierDO.setUseStatus(Objects.equals("使用",vo.getFStatus_FName())?1:0);
            if (allOldIds.containsKey(id)) {
                updateSupplier.add(supplierDO);
            }else{
                saveSupplier.add(supplierDO);
            }
        }
        return Pair.of(saveSupplier,updateSupplier);
    }


/**----------------------------------------------------------------------------------------------------------------------- */

    /**
     * 同步 kis 部门
     */
    @Override
    public R departDataByParam(int itemClassId) {
        String key = ShiroUtils.getUserId() + "_allSupplier";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("禁止频繁操作同步！请60秒后重试");
        }
        //同一个登录人60秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 60l, TimeUnit.SECONDS);

        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId,true);
        //TODO   上线改为 5000
        paramForApi.put("PageSize", "1000");
        return this.doPostOfApiForDepart(kisApiUrlParam.getUrl_basic(), paramForApi);
    }

    public R doPostOfApiForDepart(String url, Map<String, String> params) {
        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<KisDepartVO> kisDepartVO = JSON.parseArray(datas, KisDepartVO.class);
            if (!CollectionUtils.isEmpty(kisDepartVO)) {
                //单线程保存 更新
                keepUpdateForDepart(kisDepartVO);
            }
            //异步处理 id_path;id_path为 0000 的需要生成或重新生成
            createOrUpdateIdPath();
        }
        return R.ok();
    }

    //创建或更新  id_path  异步
    @Async("createPDFExecutor")
    public void createOrUpdateIdPath() {
        Map<String, Object> map = Maps.newHashMapWithExpectedSize(1);
        map.put("idPath","0000");
        List<DeptDO> sysDept = basicsDao.getDepartByIdPath(map);
        //TODO
        if (!CollectionUtils.isEmpty(sysDept)) {
            for(DeptDO deptDO:sysDept){
                    Long deptId = deptDO.getDeptId();
                    Long parentId = deptDO.getParentId();
                    if (parentId == 0) {
                        deptDO.setIdPath("/" + parentId + "/" + deptId + "/");
                    } else {
                        DeptDO parentDept = sysDeptService.get(parentId);
                        deptDO.setIdPath(parentDept.getIdPath() + deptId + "/");
                    }
            }
            //更新
            int ii = basicsDao.batchUpdateDepart(sysDept);
            log.info("---------------更新 id_path 完成 -- " + ii);
        }
    }

    public void keepUpdateForDepart(List<KisDepartVO> kisDepartVO) {
        log.info(" 保存更新 部门  开始！");
        //字段匹配转换
        Pair<List<DeptDO>, List<DeptDO>> DepartDOs = fieldMatchingConversionOfDepart(kisDepartVO);
        try {
            List<DeptDO> updateSupplier = DepartDOs.getRight();
            if (!CollectionUtils.isEmpty(updateSupplier)) {
                int i = basicsDao.batchUpdateDepart(updateSupplier);
                log.info("---------------更新-完成 - " + i);
            }
            List<DeptDO> saveSupplier = DepartDOs.getLeft();
            if (!CollectionUtils.isEmpty(saveSupplier)) {
                int ii = basicsDao.batchSaveDepart(saveSupplier);
                log.info("---------------保存 完成 -- " + ii);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新 部门  异常！");
        }
        log.info(" 保存更新 部门  结束！");
    }

    public  Pair<List<DeptDO>,List<DeptDO>> fieldMatchingConversionOfDepart(List<KisDepartVO> kisDepartVO) {
        //查询出用户的所有的主键
        Map<Long, String> allOldIds = getAllOldIdsBySign(2);
        Date date = new Date();
        List<DeptDO>  updateDate= new ArrayList<>();
        List<DeptDO> saveDate = new ArrayList<>();
        for (KisDepartVO vo : kisDepartVO) {
            DeptDO deptDO = new DeptDO();
            Long id = Long.parseLong(vo.getFItemId());
            deptDO.setDeptId(id);
            String parentId = vo.getFParentId();
            deptDO.setParentId(Long.parseLong(parentId));
            deptDO.setName(vo.getFName());
            deptDO.setUpdateTime(date);
            //是否删除
            deptDO.setDelFlag(0);
            deptDO.setDeptCode(vo.getFNumber());
            deptDO.setDeptLeader(Long.parseLong(vo.getFManager()));
            //部门类型 字典
//            deptDO.setType(Long.parseLong(vo.getFDProperty()));
            // 部门路由  id_path  是否需要重置
            if (allOldIds.containsKey(id)) {
                String value = allOldIds.get(id);
                if(!Objects.equals(parentId,value)){
                    deptDO.setIdPath("0000");
                }
                //更新不设置id_path的值则更新后保留原值
                updateDate.add(deptDO);
            }else{
                deptDO.setIdPath("0000");
                saveDate.add(deptDO);
            }
        }
        return Pair.of(saveDate,updateDate);
    }


/**----------------------------------------------------------------------------------------------------------------------- */

    /**
     * 同步 kis 即时库存
     */
    @Override
    public R realTimeStockBalanceEnquiry() {
        String key = ShiroUtils.getUserId() + "_realTimeStockBalanceEnquiry";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("禁止频繁操作同步！请60秒后重试");
        }
        //同一个登录人60秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 60l, TimeUnit.SECONDS);
        return this.doPostOfApiForStock(kisApiUrlParam.getUrl_push_stock());
    }

    /**
     * 查询 kis 即时库存
     */
    @Override
    public Triple<Boolean, String, List<KisReceiveStockVo>> realTimeStockBalanceEnquiry2(String filter) {
        return this.doPostOfApiForStock2(kisApiUrlParam.getUrl_push_stock(), filter);
    }

    /**
     * 查询 kis 即时库存
     */
    @Override
    public Triple<Boolean, String, List<KisReceiveStockVo>> realTimeStockBalanceEnquiry222(String filter) {
        return this.doPostOfApiForStock222(kisApiUrlParam.getUrl_push_stock(), filter);
    }

    //查询出用户的所有的主键 及 标记
    public  Map<String,Long> getAllOldIdsAndSignOfStock(){
        List<Map<String, Object>> allIdAndUniqueness = kisStockService.getAllIdAndUniqueness();
        Map<String,Long> map = new HashMap<>();
        if(!CollectionUtils.isEmpty(allIdAndUniqueness)){
            allIdAndUniqueness.stream().forEach(aa->{
                map.put(aa.get("uniqueness").toString(),Long.parseLong(aa.get("id").toString()));
            });
        }
        return map;
    }

    public R doPostOfApiForStock(String url) {
        Map<String, String> paramForApi = new HashMap<>();
        paramForApi.put("Acct", JiateConstant.ACCT);
        paramForApi.put("PageNo", "1");
        paramForApi.put("PageSize", "500");
        for (int i = 1; i < 200; i++) {
            paramForApi.put("PageNo", String.valueOf(i));
            log.info("参数："+JSONObject.toJSONString(paramForApi));

            String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(paramForApi));
            if (StringUtils.isNotBlank(result)) {
                Object parse = JSON.parse(result);
                ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
                log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
                if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                    // 0 为正常  1 异常
                    log.info("同步即时库存api 返回值状态码异常" + apiResultVOS.getMsg());
                    return R.error("同步即时库存api 返回值状态码异常：" + apiResultVOS.getMsg());
                }
                String datas = apiResultVOS.getDatas();
                List<KisReceiveStockVo> kisReceiveStockVo = JSON.parseArray(datas, KisReceiveStockVo.class);
                if (!CollectionUtils.isEmpty(kisReceiveStockVo)) {
                    log.info("转换的datas：" + kisReceiveStockVo);
                    //单线程保存 更新
                    this.keepUpdateForStock(kisReceiveStockVo);
                } else {
                    break;
                }
            }
        }
        return R.ok();
    }

    /**
     * 将金蝶API改为第三方接口
     *
     * @param url
     * @return
     */
    public Triple<Boolean, String, List<KisReceiveStockVo>> doPostOfApiForStock2(String url, String filter) {
        Map<String, String> paramForApi = new HashMap<>();
        paramForApi.put("Acct", JiateConstant.ACCT);
        paramForApi.put("PageNo", "1");
        paramForApi.put("filter", ObjectUtils.isEmpty(filter) ? "" : filter);
        paramForApi.put("PageSize", "500");
        paramForApi.put("PageNo", "1");
        log.info("参数："+JSONObject.toJSONString(paramForApi));

        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(paramForApi));
        if (StringUtils.isBlank(result)) {
            return Triple.of(false, "查询失败" ,null);
        }
        Object parse = JSON.parse(result);
        ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
        if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
            // 0 为正常  1 异常
            log.info("同步即时库存api 返回值状态码异常" + apiResultVOS.getMsg());
            return Triple.of(false, apiResultVOS.getMsg() ,null);
        }
        String datas = apiResultVOS.getDatas();
        List<KisReceiveStockVo> kisReceiveStockVo2 = new ArrayList<>();

        JSONArray dataArray = JSONObject.parseArray(datas);
        if (ObjectUtils.isEmpty(dataArray) || dataArray.size() <= 0){
            return Triple.of(true, apiResultVOS.getMsg() ,kisReceiveStockVo2);
        }
        for (int i = 0; i < dataArray.size(); i++) {
            try {
                JSONObject value = JSONObject.parseObject(dataArray.get(i).toString());
                KisReceiveStockVo vo = new KisReceiveStockVo();
                vo.setFItemID(ObjectUtil.isNotEmpty(value.get("物料ID")) ? value.get("物料ID").toString() : "0");
                vo.setFItemName(ObjectUtil.isNotEmpty(value.get("物料名称")) ? value.get("物料名称").toString() : "0");
                vo.setFBatchNo(ObjectUtil.isNotEmpty(value.get("批号")) ? value.get("批号").toString() : "");
                vo.setFQty(ObjectUtil.isNotEmpty(value.get("数量")) ? value.get("数量").toString() : "0");
                vo.setFStockID(ObjectUtil.isNotEmpty(value.get("仓库ID")) ? value.get("仓库ID").toString() : "");
                vo.setFStockId_FName(ObjectUtil.isNotEmpty(value.get("仓库名称")) ? value.get("仓库名称").toString() : "");
                vo.setFStockPlaceID(ObjectUtil.isNotEmpty(value.get("仓位ID")) ? value.get("仓位ID").toString() : "");
                vo.setFStockPlaceID_FName(ObjectUtil.isNotEmpty(value.get("仓位名称")) ? value.get("仓位名称").toString() : "");
                vo.setFModel(ObjectUtil.isNotEmpty(value.get("规格型号")) ? value.get("规格型号").toString() : "");
                vo.setUnitName(ObjectUtil.isNotEmpty(value.get("计量单位名称")) ? value.get("计量单位名称").toString() : "");
                vo.setMaterialCode(ObjectUtil.isNotEmpty(value.get("物料代码")) ? value.get("物料代码").toString() : "");
                vo.setFRECORDS(ObjectUtil.isNotEmpty(value.get("FRECORDS")) ? value.get("FRECORDS").toString() : "0");
                kisReceiveStockVo2.add(vo);
            } catch (Exception e) {
                log.info("----one  数据解析出现异常：");
            }
        }

        log.info("-------------返回值   整理1  ----kisReceiveStockVo2:" + kisReceiveStockVo2);
//        List<KisReceiveStockVo> kisReceiveStockVo = JSON.parseArray(datas, KisReceiveStockVo.class);
        return Triple.of(true, apiResultVOS.getMsg() ,kisReceiveStockVo2);
    }
    /**
     * 将金蝶API改为第三方接口
     *
     * @param url
     * @return
     */
    public Triple<Boolean, String, List<KisReceiveStockVo>> doPostOfApiForStock222(String url, String filter) {
        Map<String, String> paramForApi = new HashMap<>();
        paramForApi.put("Acct", JiateConstant.ACCT);
        paramForApi.put("PageNo", "1");
        paramForApi.put("filter", ObjectUtils.isEmpty(filter) ? "" : filter);
        paramForApi.put("PageSize", "50000");
        paramForApi.put("PageNo", "1");
        log.info("参数："+JSONObject.toJSONString(paramForApi));

        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(paramForApi));
        if (StringUtils.isBlank(result)) {
            return Triple.of(false, "查询失败" ,null);
        }
        Object parse = JSON.parse(result);
        ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
        if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
            // 0 为正常  1 异常
            log.info("同步即时库存api 返回值状态码异常" + apiResultVOS.getMsg());
            return Triple.of(false, apiResultVOS.getMsg() ,null);
        }
        String datas = apiResultVOS.getDatas();
        List<KisReceiveStockVo> kisReceiveStockVo2 = new ArrayList<>();

        JSONArray dataArray = JSONObject.parseArray(datas);
        if (ObjectUtils.isEmpty(dataArray) || dataArray.size() <= 0){
            return Triple.of(true, apiResultVOS.getMsg() ,kisReceiveStockVo2);
        }
        for (int i = 0; i < dataArray.size(); i++) {
            try {
                JSONObject value = JSONObject.parseObject(dataArray.get(i).toString());
                KisReceiveStockVo vo = new KisReceiveStockVo();
                vo.setFItemID(ObjectUtil.isNotEmpty(value.get("物料ID")) ? value.get("物料ID").toString() : "0");
                vo.setFItemName(ObjectUtil.isNotEmpty(value.get("物料名称")) ? value.get("物料名称").toString() : "0");
                vo.setFBatchNo(ObjectUtil.isNotEmpty(value.get("批号")) ? value.get("批号").toString() : "");
                vo.setFQty(ObjectUtil.isNotEmpty(value.get("数量")) ? value.get("数量").toString() : "0");
                vo.setFStockID(ObjectUtil.isNotEmpty(value.get("仓库ID")) ? value.get("仓库ID").toString() : "");
                vo.setFStockId_FName(ObjectUtil.isNotEmpty(value.get("仓库名称")) ? value.get("仓库名称").toString() : "");
                vo.setFStockPlaceID(ObjectUtil.isNotEmpty(value.get("仓位ID")) ? value.get("仓位ID").toString() : "");
                vo.setFStockPlaceID_FName(ObjectUtil.isNotEmpty(value.get("仓位名称")) ? value.get("仓位名称").toString() : "");
                vo.setFModel(ObjectUtil.isNotEmpty(value.get("规格型号")) ? value.get("规格型号").toString() : "");
                vo.setUnitName(ObjectUtil.isNotEmpty(value.get("计量单位名称")) ? value.get("计量单位名称").toString() : "");
                vo.setMaterialCode(ObjectUtil.isNotEmpty(value.get("物料代码")) ? value.get("物料代码").toString() : "");
                vo.setFRECORDS(ObjectUtil.isNotEmpty(value.get("FRECORDS")) ? value.get("FRECORDS").toString() : "0");
                kisReceiveStockVo2.add(vo);
            } catch (Exception e) {
                log.info("----one  数据解析出现异常：");
            }
        }

        log.info("-------------返回值   整理1  ----kisReceiveStockVo2:" + kisReceiveStockVo2);
//        List<KisReceiveStockVo> kisReceiveStockVo = JSON.parseArray(datas, KisReceiveStockVo.class);
        return Triple.of(true, apiResultVOS.getMsg() ,kisReceiveStockVo2);
    }

    public void keepUpdateForStock(List<KisReceiveStockVo> kisReceiveStockVo){
        Map<String,Long> allOldIdsAndSignOfStock =this.getAllOldIdsAndSignOfStock();
        List<KisStockDO> updateVO = new ArrayList<>();
        List<KisStockDO> saveVO = new ArrayList<>();
        kisReceiveStockVo.stream().forEach(aa->{
            KisStockDO kisStockDO = new KisStockDO();
            kisStockDO.setFitemid(Long.parseLong(aa.getFItemID()));
            kisStockDO.setFname(aa.getFName()==""||aa.getFName()==null?"-":aa.getFName());
            kisStockDO.setFbatchno(aa.getFBatchNo()==""||aa.getFBatchNo()==null?null:aa.getFBatchNo());
            kisStockDO.setFmodel(aa.getFModel()==""||aa.getFModel()==null?null:aa.getFModel());
            kisStockDO.setFnumber(aa.getFNumber()==""||aa.getFNumber()==null?null:aa.getFNumber());
            kisStockDO.setFqty(new BigDecimal(aa.getFQty()==""||aa.getFQty()==null?"0":aa.getFQty()));
            kisStockDO.setFsecqty(new BigDecimal(aa.getFSecQty()==""||aa.getFSecQty()==null?"0":aa.getFSecQty()));
            kisStockDO.setFstockId(Long.parseLong(aa.getFStockID()==""||aa.getFStockID()==null?"0":aa.getFStockID()));
            kisStockDO.setFstockidFname(aa.getFStockId_FName()==""||aa.getFStockId_FName()==null?null:aa.getFStockId_FName());
            kisStockDO.setFstockplaceId(Long.parseLong(aa.getFStockPlaceID()));
            kisStockDO.setFstockplaceidFname(aa.getFStockPlaceID_FName()==""||aa.getFStockPlaceID_FName()==null?null:aa.getFStockPlaceID_FName());
            kisStockDO.setFkfperiod(aa.getFKFPeriod()==""||aa.getFKFPeriod()==null?null:aa.getFKFPeriod());
           if(aa.getFKFDate()==""||aa.getFKFDate()==null?false: true){
               kisStockDO.setFkfdate(timeToTranslateForDate(aa.getFKFDate()));
           }
            //唯一性标记并根据唯一性判断更新或者保存
           String uniqueness =  aa.getFItemID()+aa.getFBatchNo()+aa.getFStockID()+aa.getFStockPlaceID();
            kisStockDO.setUniqueness(uniqueness);
           if(allOldIdsAndSignOfStock.containsKey(uniqueness)){
               kisStockDO.setId(allOldIdsAndSignOfStock.get(uniqueness));
               updateVO.add(kisStockDO);
           }else{
               kisStockDO.setUniqueness(uniqueness);
               saveVO.add(kisStockDO);
           }
        });
        if(!CollectionUtils.isEmpty(updateVO)){
            kisStockService.batchUpdate(updateVO);
        }
        if(!CollectionUtils.isEmpty(saveVO)){
            log.info("转换新增实体saveVO：" + JSONObject.toJSONString(saveVO));
            int i = kisStockService.batchSave(saveVO);
            log.info("----------保存成功行数:"+i);
        }

    }


    /**----------------------------------------------------------------------------------------------------------------------- */

    /**
     * 同步 kis 计量单位   与物料绑定一起更新
     */
    @Async("createPDFExecutor")
    @Override
    public R unitOfMeasurement() {
        String key ="unit_of_measurement_key";
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return R.error("禁止频繁操作同步！请60秒后重试");
        }
        //180秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 180l, TimeUnit.SECONDS);

        Map<String, String> paramForApi = ApiParam.paramApiForBasics(JiateConstant.UNIT,true);
        return this.doPostOfApiForStock(kisApiUrlParam.getUrl_base_data(),paramForApi);
    }

    public R doPostOfApiForStock(String url, Map<String, String> params) {
        //自定义获取数量
        params.put("PageSize","1000");
        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            log.info("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<KisUnitVo> kisUnitVo = JSON.parseArray(datas, KisUnitVo.class);
            if (!CollectionUtils.isEmpty(kisUnitVo)) {
                //单线程保存 更新
                keepUpdateForUnit(kisUnitVo);
            }
        }
        return R.ok();
    }

   public void  keepUpdateForUnit(List<KisUnitVo> kisUnitVo){
        //之前同步的老数据
       Date date = new Date();
       Map<Long, String> allOldIds = getAllOldIdsBySign(JiateConstant.UNIT);
       List<DictionaryDO> updateVO = new ArrayList<>();
       List<DictionaryDO> saveVO = new ArrayList<>();
       for (KisUnitVo aa : kisUnitVo) {
           DictionaryDO vo = new DictionaryDO();
           vo.setName(aa.getFName());
           vo.setValue(aa.getFNameEN());
           vo.setTypeId(JiateConstant.UOM_TYPE_KEY);
           vo.setCreateBy(1L);
           vo.setCreateTime(date);
           vo.setDelFlag(0);
           long measureUnitId = Long.parseLong(aa.getFMeasureUnitId());
           vo.setMeasureUnitId(measureUnitId);
           if(allOldIds.containsKey(measureUnitId)){
               vo.setId(Long.parseLong(allOldIds.get(measureUnitId)));
               updateVO.add(vo);
           }else{
               saveVO.add(vo);
           }
       }
       if(!CollectionUtils.isEmpty(saveVO)){
           basicsDao.batchSaveDictionary(saveVO);
       }
       if(!CollectionUtils.isEmpty(updateVO)){
           basicsDao.batchUpdateDictionary(updateVO);
       }
       log.info("---------------计量单位全部处理结束！");
   }

    @PostConstruct
    public void start() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("typeId", 200);
        List<DictionaryDO> list = dictionaryService.list(map);
        DictionaryDO dic;
        for (int i = 0; i < list.size(); i++) {
            dic = list.get(i);
            if ("成型日报原料投入量领料车间库".equals(dic.getName())) {
                Constant.warehouse2 = new Long(dic.getValue());
                log.error("==========================成型日报原料投入量领料车间库:{}",dic.getValue());
            }
            if ("成型日报不良数量入库不良品库".equals(dic.getName())) {
                Constant.warehouse3 = new Long(dic.getValue());
                log.error("==========================成型日报不良数量入库不良品库:{}",dic.getValue());
            }
//            if ("成型日报不良数量入库不良品库位".equals(dic.getName())) {
//                Constant.warehLocation3 = new Long(dic.getValue());
//            }
            if ("成型日报生产数量-不良数量入库车间库".equals(dic.getName())) {
                Constant.warehouse4 = new Long(dic.getValue());
                log.error("==========================成型日报生产数量-不良数量入库车间库:{}",dic.getValue());
            }
//            if ("成型日报生产数量-不良数量入库车间库位".equals(dic.getName())) {
//                Constant.warehLocation4 = new Long(dic.getValue());
//            }
            if ("组装日报使用数量领料车间库".equals(dic.getName())) {
                Constant.warehouse6 = new Long(dic.getValue());
                log.error("==========================组装日报使用数量领料车间库:{}",dic.getValue());
            }
            if ("组装日报不良数量入库不良品库".equals(dic.getName())) {
                Constant.warehouse7 = new Long(dic.getValue());
                log.error("==========================组装日报不良数量入库不良品库:{}",dic.getValue());
            }
            if ("组装日报不良数量入库不良品库位".equals(dic.getName())) {
                Constant.warehLocation7 = new Long(dic.getValue());
            }
            if ("组装日报合格数量入库车间库".equals(dic.getName())) {
                Constant.warehouse8 = new Long(dic.getValue());
                log.error("==========================组装日报合格数量入库车间库:{}",dic.getValue());
            }
            if ("组装日报合格数量入库车间库位".equals(dic.getName())) {
                Constant.warehLocation9 = new Long(dic.getValue());
                log.error("==========================组装日报合格数量入库车间库位:{}",dic.getValue());
            }
        }
    }
}
